using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using Env = SsLib.Environment;

namespace SsLib
{
    public class BasicIO : Environment
    {
        internal static BasicIO _outer;

        internal List<File> _openFiles = new List<File>();

        /// <summary>
        /// File is the common prefix class for all input/output classes.
        /// </summary>
        public abstract class File : SimObject
        {

            protected const int DEFAULT_BYTESIZE = 8;

            /// <summary>The name of the external file.</summary>
            private Text FILENAME;

            /// <summary>This flag indicates whether the file is open.</summary>
            protected bool OPEN = false;

            /// <summary>The external stream this object is associated with.</summary>
            protected Stream stream = null;

            //Access mode flags: (modified through SetAccess)
            protected bool SHARED = false;
            protected bool APPEND = false;
            protected bool CREATE = false;
            protected bool ANY = false;
            protected bool READ = false;
            protected bool WRITE = false;
            protected bool REWIND = false;
            protected bool PURGE = false;
            protected short BYTESIZE = DEFAULT_BYTESIZE;

            public abstract bool Close();

            #region protected and shared members
            /// <summary>
            /// The OpenFile method implements the common open file behaviour of File class implementers.
            /// It serves as a common stub (shared functionalite).
            /// It establishes the association with an external file. (I.e. opens a stream to the file).
            /// It file is allready open, just returns true.
            /// </summary>
            /// <returns>True on success, otherwise false.</returns>
            protected bool OpenFile()
            {
                if (!this.OPEN)
                {
                    try
                    {
                        this.stream = OpenStreamImpl();
                        _outer._openFiles.Add(this);
                    }
                    catch
                    {
                        //swallow any open file stream exceptions and return false
                        return false;
                    }
                }
                return true;
            }

            /// <summary>
            /// OpenStreamImpl is abstract and must be implemented by File subclass implementers.
            /// Opens a stream to the external file this object is associated using the appropriate access modes. 
            /// </summary>
            /// <returns>The opened stream to the external file.</returns>
            protected abstract System.IO.Stream OpenStreamImpl();

            /// <summary>
            /// The CloseFile method implements the common close file behaviour of File class implementers.
            /// It serves as a common stub (shared functionalite).
            /// It dissolves s the association with an external file. (I.e. closes the stream to the file).
            /// It file is allready closed, just returns true;
            /// </summary>
            /// <returns>True on success, otherwise false.</returns>
            protected bool CloseFile()
            {
                if (this.OPEN)
                {
                    //Tapes are obolete so rewind is not implemented

                    CloseStreamImpl();

                    _basicio._openFiles.Remove(this);

                    stream.Close();
                    stream = null;
                    
                    //Perform purging if requested in access modes
                    if (this.PURGE)
                    {
                        System.IO.File.Delete(this.FileName().ToString());
                    }
                }
                return true;
            }

            /// <summary>
            /// CloseStreamImpl is abstract and must be implemented by File subclass implementers.
            /// It dissolves s the association with an external file. (I.e. closes the stream to the file).
            /// </summary>
            protected abstract void CloseStreamImpl();
            #endregion

            #region public memberss
            /// <summary>
            /// Constructor for File class.
            /// </summary>
            /// <remarks>
            /// filename is value transfered according to SIMULA86, ch.10 The class file.
            /// This is implemented in typical Sim# style on the inside of the procedure so the caller do not have to 
            /// worry about this.
            /// </remarks>
            /// <param name="filename">Name of the external file to assosiate with the file object.</param>
            public File(Text filename)
            {
                if (FILENAME.Equals(Text.NoText)) Error("File: Illegal filename - NoText.");

                //value assignment of FILENAME
                FILENAME = _outer.Blanks(filename.Length());
                FILENAME.SetValue(filename);
            }

            /// <summary>
            /// Returns a Text value with the name of the external file assosiated with the File object.
            /// </summary>
            /// <returns>Name of external file.</returns>
            public Text FileName()
            {
                return _basicio.Copy(FILENAME);
            }

            /// <summary>
            /// Returns the current open status of the external file. 
            /// Returns true if external file is open, false otherwise.
            /// </summary>
            /// <returns>Open status of the external file.</returns>
            public bool IsOpen()
            {
                return OPEN;
            }

            /// <summary>
            /// Sets an access mode flag on the current file object. 
            /// The flags are used in File.Open and File.Close procedures.
            /// </summary>
            /// <remarks>
            /// Certain attributes (not specified in the file outline) control the access to the external file. 
            /// The values of these attributes are set when the file object is opened or closed, from a set of 
            /// default values possibly modified by successive calls to the procedure "setaccess". 
            /// 
            /// The standard attribute modes are SHARED, APPEND, CREATE, READWRITE, BYTESIZE, REWIND and PURGE.
            /// 
            /// The parameter "mode" to procedure "setaccess" contains one of the standard values as given above, 
            /// namely "shared", "noshared", "append", "noappend", "create", "nocreate", "anycreate", "readonly", 
            /// "writeonly", "readwrite", "bytesize:X" (where X is a positive integer), "rewind", "norewind", 
            /// "purge" and "nopurge".
            /// 
            /// The parameter "bytesize:0" (zero) specifies the (implementation-defined) default byte size for bytefiles,
            /// which is 8 bits.
            /// 
            /// Only one mode may be specified in each "setaccess" call, the case of the individual letters of 
            /// the parameter being insignificant. Unrecognized modes are ignored and "setaccess" then returns 
            /// the value false. The value is true otherwise. A specific mode is interpreted either at next 
            /// "open" or next "close". A mode which is set after "open" or "close" has no effect until the next 
            /// "close" or "open" respectively.
            /// </remarks>
            /// <param name="mode"></param>
            /// <returns></returns>
            public bool SetAccess(Text mode)
            {
                string s = mode.ToString();
                if (s.Equals("shared", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.SHARED = true; return true;
                }
                if (s.Equals("noshared", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.SHARED = false; return true;
                }                
                if (s.Equals("append", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.APPEND = true; return true;
                }
                if (s.Equals("noappend", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.APPEND = false; return true;
                }
                if (s.Equals("create", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.CREATE = true; 
                    this.ANY = false;
                    return true;
                }
                if (s.Equals("nocreate", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.CREATE = false; 
                    this.ANY = false;
                    return true;
                }
                if (s.Equals("anycreate", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.CREATE = false; 
                    this.ANY = true;
                    return true;
                }
                if (s.Equals("readonly", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.READ = true; 
                    this.WRITE = false;
                    return true;
                }
                if (s.Equals("writeonly", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.READ = false; 
                    this.WRITE = true;
                    return true;
                }
                if (s.Equals("readwrite", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.READ = true;
                    this.WRITE = true;
                    return true;
                }
                if (s.Equals("rewind", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.REWIND = true; return true;
                }
                if (s.Equals("norewind", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.REWIND = false; return true;
                }
                if (s.Equals("purge", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.PURGE = true; return true;
                }
                if (s.Equals("nopurge", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.PURGE = false; return true;
                }
                if (s.StartsWith("bytesize:", StringComparison.InvariantCultureIgnoreCase))
                {
                    bool success = false;
                    short bs; 
                    success = short.TryParse(s.Remove(0, 9), out bs);
                    if (bs == 0) bs = DEFAULT_BYTESIZE;
                    if (bs < 0) success = false;
                    else this.BYTESIZE = bs;
                    return success;
                }
                return false;
            }
            #endregion
        }

        /// <summary>
        /// The ImageFile class defines the common attributes for all image-oriented files.
        /// </summary>
        public abstract class ImageFile : File
        {
            #region public members
            /// <summary>
            /// ImageFile constructor.
            /// </summary>
            /// <param name="filename">Name of external file.</param>
            public ImageFile(Text filename) : base(filename) { }

            /// <summary>Buffer text frame for current external image.</summary>
            public Text Image;
            /// <summary>
            /// Sets position in the text frame buffer.
            /// </summary>
            /// <param name="i">Position to set.</param>
            public void SetPos(int i) { Image.SetPos(i); }
            /// <summary>
            /// Returns the current position in the text frame buffer.
            /// </summary>
            /// <returns>Current position in text frame buffer.</returns>
            public int Pos() { return Image.Pos(); }
            /// <summary>
            /// Returns a value indicating if there is more space left in the text frame buffer.
            /// Returns true if there is text frame buffer is longer than the current position.
            /// Otherwise returns false.
            /// </summary>
            /// <returns>A value indicating if there is more space left in the text frame buffer.</returns>
            public bool More() { return Image.More(); }
            /// <summary>
            /// Returns the length of the text frame buffer.
            /// </summary>
            /// <returns>The length of the text frame buffer.</returns>
            public int Length() { return Image.Length(); }
            #endregion
        }

        /// <summary>
        /// The InFile class is used to represent an image-oriented sequential input file.
        /// </summary>
        /// <remarks>
        /// The attribute EndFile is true whenever the object is closed or the external
        /// file is exhausted (i.e. end-of-file has been encountered).
        /// </remarks>
        public class InFile : ImageFile
        {
            /// <summary>A reader surrounding the current file stream.</summary>
            protected StreamReader reader = null;
            
            /// <summary>
            /// ENDFILE is true if the file is closed or the external file is at end-of-file
            /// </summary>
            private bool ENDFILE = true;

            #region protected members
            /// <summary>
            /// Opens a stream to the external file this object is associated using the appropriate access modes. 
            /// </summary>
            /// <returns>The opened stream to the external file.</returns>
            protected override Stream OpenStreamImpl()
            {
                string fileName = this.FileName().ToString();
                Stream s;

                //special case, if the filename is stdin, then console standard input is used as file stream.
                if (fileName == "stdin")
                {
                    s = Console.OpenStandardInput();
                }
                else
                {
                    //create mode is not applicable to in-files
                    //append mode is not applicable to in-files.
                    FileMode filemode = FileMode.Open;

                    //shared mode is applicable to in-files
                    FileShare fileshare;
                    if (this.SHARED) fileshare = FileShare.ReadWrite;
                    else fileshare = FileShare.None;

                    //File access is not applicable to in-files.
                    FileAccess fileaccess = FileAccess.Read;

                    s = System.IO.File.Open(fileName, filemode, fileaccess, fileshare);
                }
                this.reader = new StreamReader(s);
                return this.reader.BaseStream;
            }

            /// <summary>
            /// CloseStreamImpl is abstract and must be implemented by File subclass implementers.
            /// It dissolves s the association with an external file. (I.e. closes the stream to the file).
            /// </summary>
            protected override void CloseStreamImpl()
            {
                this.reader.Close();
                this.reader = null;
            }
            #endregion

            #region public members
            /// <summary>
            /// Creates a new InFile object.
            /// </summary>
            /// <remarks>
            /// The default access mode flags for InFile objects is SHARED.
            /// </remarks>
            /// <param name="filename">The name of the external file to assosiate with this object.</param>
            public InFile(Text filename) : base(filename)
            {
                this.SHARED = true;
            }

            /// <summary>
            /// Returns a value indicating if the file is exhasted.
            /// Returns true if end-of-file is reached or if the file is closed.
            /// Otherwise returns false;
            /// </summary>
            /// <returns>A value indicating of the file is exhausted.</returns>
            public bool EndFile() { return ENDFILE; }

            /// <summary>
            /// Assosiates the file object with an external file and opens the file.
            /// Returns true upon success.
            /// </summary>
            /// <param name="fileimage">The text frame to use as a buffer.</param>
            /// <returns>True if open succeeds, otherwise false.</returns>
            public bool Open(Text fileimage)
            {
                if (OpenFile())
                {
                    ENDFILE = false;
                    Image = fileimage;
                    Image.SetValue(Text.NoText);  //fills the text frame with spaces
                    SetPos(Length() + 1);
                    this.OPEN = true;
                }
                return OPEN;
            }

            /// <summary>
            /// Procedure "close" causes closing actions on the external file, as specified by the access modes. 
            /// In addition, the association between the file object and the external file is dissolved. 
            /// If possible, the external file is closed.
            /// Returns true upon success.
            /// </summary>
            /// <returns>true if close succeeds, otherwise false.</returns>
            public override bool Close()
            {
                if (CloseFile())
                {
                    Image = Text.NoText;
                    OPEN = false;
                    ENDFILE = true;
                }
                return ENDFILE;
            }

            /// <summary>
            /// InImage transfers an external file image into Image.
            /// </summary>
            /// <remarks>
            /// A run-time error occurs if "image" is notext or too short to contain the external image. 
            /// If it is longer than the external image, the latter is left-adjusted within "image" 
            /// and the remainder of the text is filled with spaces. 
            /// The position indicator is set to one.  
            /// </remarks>
            public void InImage()
            {
                if (!OPEN || ENDFILE) Error("InImage: File is not open or end-of-file");
                //transfer expternal file into image
                string buf;
                int i = 0;
                //if no more to read from external file
                if (reader.EndOfStream)
                //if (i == 0)
                {
                    ENDFILE = true;
                    Image.SetValue(Text.NoText);  //blank the Image.
                    Image.OBJ.MAIN[Image.START - 1] = (char)25;
                }
                else
                {
                    buf = this.reader.ReadLine();
                    if (buf != null)
                    {
                        i = buf.Length;

                        //if image is too small then Error("file is to big for image");
                        if (i > this.Image.LENGTH) Error("InImage: Buffer is too short to hold the input image");

                        buf.CopyTo(0, Image.OBJ.MAIN, Image.START - 1, i);
                    }

                    //Pad remaining part of this text frame with spaces.
                    for (int n = this.Image.START - 1 + i; n < this.Image.LENGTH - 1; n++)
                        this.Image.OBJ.MAIN[n] = ' ';
                }
                SetPos(1);
            }

            /// <summary>
            /// InRecord transfers an external file image into Image.
            /// Any overflow is pushed back into the stream and true is returned to signal overflow
            /// </summary>
            /// <remarks>
            /// The procedure InRecord is similar to InImage with the following exceptions. 
            /// Whenever the number of characters accessible in the external image is less than "length", 
            /// the rest of "image" is left unchanged. The part of the "image" that was changed is from 
            /// pos 1 upto (but not including) the resulting value of POS. Moreover, if the external image is 
            /// too long, only the "length" first characters are input. The value returned by the procedure 
            /// is true and the remaining characters may be input through 
            /// subsequent "inrecord" (or possibly "inimage") statements. 
            /// Otherwise, if the input of the external image was completed, the value false is returned.
            /// 
            /// Note: If an "end of file" is encountered, EM ('!25!') is generated as a single character external image, 
            /// and the variable ENDFILE is given the value true. 
            /// A call on "inimage" or "inrecord" when ENDFILE already has the value true constitutes a run-time error.
            /// </remarks>
            /// <returns></returns>
            public bool InRecord()
            {
                if (!OPEN || ENDFILE) Error("InRecord: File is not open or end-of-file");

                bool retval = false;

                //transfer expternal file into image
                string buf;
                int i = 0;
                //if no more to read from external file
                if (reader.EndOfStream)
                //if (i == 0)
                {
                    ENDFILE = true;
                    Image.SetValue(Text.NoText);  //blank the Image.
                    Image.OBJ.MAIN[Image.START - 1] = (char)25;
                }
                else
                {
                    buf = this.reader.ReadLine();
                    if (buf != null)
                    {
                        i = buf.Length;

                        //if image is too small then Error("file is to big for image");
                        if (i > this.Image.LENGTH)
                        {
                            int diff = this.Image.LENGTH - i;
                            this.reader.BaseStream.Seek(diff, SeekOrigin.Current);
                            i = this.Image.LENGTH;
                            retval = true;
                        }
                        buf.CopyTo(0, Image.OBJ.MAIN, Image.START - 1, i);
                    }

                }

                return retval;
            }

            /// <summary>
            /// The procedure "inchar" gives access to and scans past the next character.
            /// </summary>
            /// <remarks> Note: The result may be the "EOF-character" EM (ISOrank 25).</remarks>
            /// <returns></returns>
            public char InChar()
            {
                if (!More()) InImage();
                return Image.GetChar();
            }

            /// <summary>
            /// Scans the external file for more charaters. Skips ahead until non space non tab character is found.
            /// Returns true of no more characters is found in file.
            /// </summary>
            /// <remarks>
            /// The purpose of the procedure "lastitem" is to skip past all SP and HT characters (ISOrank 32 and 9 respectively). 
            /// The process of scanning may involve the transfer of several successive external images. 
            /// If the file contains no further non-space, non-tab characters the value true is returned. 
            ///</remarks>
            /// <returns>True if there are no more characters is the file.</returns>
            public bool LastItem()
            {
                char c;
                c = ' ';
                while (!ENDFILE && (c == ' ' || c == '\t')) c = InChar();
                if (c != ' ') SetPos(Pos() - 1);
                return ENDFILE;
            }

            /// <summary>
            /// Returns a new image (text frame) containing the next 'w' characters in the external file.
            /// </summary>
            /// <remarks>
            /// The expression "intext(w)" where "w" is a positive integer is a reference to a new alterable main frame of length w 
            /// containing a copy of the next w characters of the file. POS is set to the following character. 
            /// The expression "intext(0)" references notext. In contrast to the item-oriented procedures (see below), 
            /// "intext" operates on a continuous stream of characters, reading several images if necessary. 
            /// 
            /// Note: The result may be a reference to an "EOF-image" (cf. 10.4.2). 
            ///</remarks>
            /// <param name="w">Number of characters to read from stream.</param>
            /// <returns>New image containing the next 'w' charaters from external file.</returns>
            public Text InText(int w)
            {
                Text t;
                t = _outer.Blanks(w);
                while (t.More()) t.PutChar(InChar());
                return t;
            }

            /// <summary>
            /// Converts the string representation of a number in the Image to an integer,
            /// starting from current possition. 
            /// </summary>
            /// <returns>An integer value converted from the Image.</returns>
            public int InInt()
            {
                if (LastItem()) Error("InInt: End of file");
                Text t;
                t = Image.Sub(Pos(), Length() - Pos() + 1);
                int i = t.GetInt();
                SetPos(Pos() + t.Pos() - 1);
                return i;
            }
            /// <summary>
            /// Converts the string representation of a number in the Image to a long real (Double),
            /// starting from current possition. 
            /// </summary>
            /// <returns>A long real value converted from the Image.</returns>
            public double InReal()
            {
                if (LastItem()) Error("InReal: End of file");
                Text t;
                t = Image.Sub(Pos(), Length() - Pos() + 1);
                double d = t.GetReal();
                SetPos(Pos() + t.Pos() - 1);
                return d;
            }
            /// <summary>
            /// Converts the string representation of a grouped number item in the Image to an integer,
            /// starting from current possition. 
            /// </summary>
            /// <returns>An integer value converted from the Image.</returns>
            public int InFrac()
            {
                if (LastItem()) Error("InReal: End of file");
                Text t;
                t = Image.Sub(Pos(), Length() - Pos() + 1);
                int i = t.GetFrac();
                SetPos(Pos() + t.Pos() - 1);
                return i;
            }
            #endregion
        }

        /// <summary>
        /// An object of the class "outfile" is used to represent an image-oriented sequential output file. 
        /// </summary>
        public class OutFile : ImageFile
        {
            /// <summary>A writer surrounding the current file stream.</summary>
            protected StreamWriter writer = null;
            /// <summary>Flag indicating of out stream is StdOut or not.</summary>
            protected bool _stdOut = false;

            #region protected members
            /// <summary>
            /// Opens a stream to the external file this object is associated using the appropriate access modes. 
            /// </summary>
            /// <returns>The opened stream to the external file.</returns>
            protected override Stream OpenStreamImpl()
            {
                Stream s;
                string fileName = this.FileName().ToString();
                if (fileName == "stdout")
                {
                    s = Console.OpenStandardOutput();
                    this._stdOut = true;
                }
                else
                {
                    s = System.IO.File.OpenWrite(fileName);
                    this._stdOut = false;
                }
                this.writer = new StreamWriter(s);
                return this.writer.BaseStream;
            }

            /// <summary>
            /// CloseStreamImpl is abstract and must be implemented by File subclass implementers.
            /// It dissolves s the association with an external file. (I.e. closes the stream to the file).
            /// </summary>
            protected override void CloseStreamImpl()
            {
                this.writer.Flush();
                this.writer.Close();
                this.writer = null;
            }
            #endregion

            /// <summary>
            /// Creates a new OutFile instance.
            /// </summary>
            /// <remarks>
            /// The default access mode flags for OutFile objects is CreateAny.
            /// </remarks>
            /// <param name="filename">The name of the external file to assosiate with this object.</param>
            public OutFile(Text filename) : base(filename) 
            {
                this.ANY = true;
            }

            /// <summary>
            /// Assosiates the file object with an external file and opens the file.
            /// Returns true upon success.
            /// </summary>
            /// <param name="fileimage">The text frame to use as a buffer.</param>
            /// <returns>>True if open succeeds, otherwise false.</returns>
            public virtual bool Open(Text fileimage)
            {
                if (OpenFile())
                {
                    this.Image = fileimage;
                    SetPos(1);
                    OPEN = true;
                }
                return OPEN;
            }

            /// <summary>
            /// Procedure "close" causes closing actions on the external file, as specified by the access modes. 
            /// In addition, the association between the file object and the external file is dissolved. 
            /// If possible, the external file is closed.
            /// Returns true upon success.
            /// </summary>
            /// <remarks>The procedure "close" calls "outimage" if the position indicator is not equal to 1.</remarks>
            /// <returns>true if close succeeds, otherwise false.</returns>
            public override bool Close()
            {
                if (Pos() != 1) OutImage();
                if (CloseFile())
                {
                    this.Image = Text.NoText;
                    this.OPEN = false;
                    return true;
                }
                else return false;
            }

            /// <summary>
            /// OutImage transfers the contents of the Image buffer to the external file.
            /// </summary>
            /// <remarks>
            /// The transfer of an image from the text "image" to the file is performed by the procedure "outimage". 
            /// The procedure reacts in an implementation-defined way if the "image" length is not appropriate for 
            /// the external file. 
            /// (Depending on file type and host system, the external file does not necessarily record trailing blanks 
            /// from the "image".) 
            /// After the transfer, "image" is cleared to blanks and the position indicator is set to 1.
            /// </remarks>
            public virtual void OutImage()
            {
                if (!OPEN) Error("OutImage: file closed.");

                //Removes any trailing blanks in the image.
                int count = Image.LENGTH;
                while (count >= Image.START && Image.OBJ.MAIN[count - 1] == ' ') count--;

                writer.WriteLine(Image.OBJ.MAIN, Image.START - 1, count);
                writer.Flush();

                Image.SetValue(Text.NoText);
                SetPos(1);
            }
            /// <summary>
            /// The procedure "outrecord" transfers to the file only that part of "image" which precedes POS. 
            /// The contents are not blanked after the transfer, although POS is set to one. 
            /// </summary>
            public virtual void OutRecord()
            {
                if (!OPEN) Error("OutRecrd: file closed.");

                this.writer.WriteLine(Image.Sub(1, Pos() - 1));
                this.writer.Flush();

                SetPos(1);
            }
            /// <summary>
            /// The procedure "breakoutimage" outputs the part of "image" that precedes POS. 
            /// The output is performed as a partial output of an external image, in the sense that implicit line terminators are suppressed. 
            /// On some external files this operation is not possible. It then has an effect identical to "outrecord". 
            /// </summary>
            /// <remarks>
            /// After transfer the "image" is blanked and POS is set to one. 
            ///
            /// One use of "breakoutimage" is to allow input from a terminal display on the same line as one on 
            /// which output (e.g. a prompt) has already been written. 
            ///</remarks>
            public void BreakOutImage()
            {
                if (!OPEN) Error("BreakOutImage: file closed.");

                this.writer.Write(Image.Sub(1, Pos() - 1));
                this.writer.Flush();

                Image.SetValue(Text.NoText);
                SetPos(1);
            }
            /// <summary>
            /// Flushes the output stream buffer to file.
            /// </summary>
            /// <remarks>
            /// All files producing output (sequential output or direct files) contain a Boolean procedure "checkpoint". 
            /// The procedure causes the environment to attempt to secure the output produced so far. 
            /// Depending on the nature of the associated external device, this causes completion of output transfer 
            /// (i.e. intermediate buffer contents are transferred). 
            /// If this is not possible or meaningful, "checkpoint" is a dummy operation in which case the value false is returned. 
            /// </remarks>
            /// <returns>True on success.</returns>
            public bool CheckPoint()
            {
                this.writer.Flush();
                return true;
            }
            /// <summary>
            /// The procedure "outchar" stores a character in the POS position of "image". 
            /// If "more" is false, "outimage" is called first. 
            /// </summary>
            /// <param name="c"></param>
            public void OutChar(char c)
            {
                if (!More()) OutImage();
                Image.PutChar(c);
            }
            /// <summary>
            /// Procedure "outtext" always transfers the complete contents of the text parameter to the file. 
            /// </summary>
            /// <param name="t"></param>
            public void OutText(Text t)
            {
                if ((Pos() > 1) && (t.Length() > Length() - Pos() + 1)) OutImage();
                t.SetPos(1);
                while (t.More()) OutChar(t.GetChar());
            }
            /// <summary>
            /// Field is an internal "handy" method creating a sub frame, inside the Image text frame, of the requested size.
            /// Field is used by the item oriented editing procedures of class OutImage.
            /// </summary>
            /// <remarks>
            /// Each item is edited into a "field" (subtext of "image") normally starting at the current accessible character. 
            /// POS is advanced correspondingly. 
            /// If the remainder of "image" is too short to contain the item, "outimage" is called implicitly prior to the editing operation. 
            /// The field is space-filled before the editing operation (inside the editing procedures). 
            /// 
            /// A run-time error occurs if a field cannot be contained within the full length of "image". 
            ///
            /// Parameter "w" determines both the length of this field and the adjustment of the item within it, as follows. 
            ///
            ///     w > 0    The field length is w, the item is right-adjusted.
            ///
            ///     w < 0    The field length is abs(w), the item is left-adjusted.
            ///
            ///     w = 0    The field length is the exact number of characters needed
            ///              to contain the item (i.e. no leading or trailing spaces).
            /// </remarks>
            /// <param name="w">Size of sub frame to create.</param>
            /// <returns>A sub frame inside Image.</returns>
            private Text Field(int w)
            {
                if (w > Length()) Error("Field: Item too long");

                if ((Pos() + w - 1) > Length()) OutImage();
                
                Text F = Image.Sub(Pos(), w);
                SetPos(Pos() + w);
                return F;
            }

            /// <summary>
            /// Outputs an Integer into Image of requested field size.
            /// </summary>
            /// <param name="i">Integer item to output into Image.</param>
            /// <param name="w">Size of item field.</param>
            public void OutInt(int i, int w)
            {
                if (w == 0) Field(w).PutInt(i);
                else if (w < 0)
                {
                    Text f;
                    f = Field(-w);
                    f.SetValue(Text.NoText);
                    f.Sub(1, w).PutInt(i);
                }
                else Field(w).PutInt(i);
            }
            /// <summary>
            /// Outputs a decimal number into Image, with specified fraction size and of requested field size.
            /// </summary>
            /// <param name="r">Long real value to output into Image.</param>
            /// <param name="n">Number of fraction digits.</param>
            /// <param name="w">Size of item field.</param>
            public void OutFix(double r, int n, int w)
            {
                if (w == 0) Field(w).PutFix(r, n);
                else if (w < 0)
                {
                    Text f;
                    f = Field(-w);
                    f.SetValue(Text.NoText);
                    f.Sub(1, w).PutFix(r, n);
                }
                else Field(w).PutFix(r, n);
            }
            /// <summary>
            /// Outputs an long real number with exponent into Image, with specified exponent size, and of requested field size.
            /// </summary>
            /// <param name="r">Long real number to output into Image.</param>
            /// <param name="n">Number of exponent part digits.</param>
            /// <param name="w">Size of item field.</param>
            public void OutReal(double r, int n, int w)
            {
                if (w == 0) Field(w).PutReal(r, n);
                else if (w < 0)
                {
                    Text f;
                    f = Field(-w);
                    f.SetValue(Text.NoText);
                    f.Sub(1, w).PutReal(r, n);
                }
                else Field(w).PutReal(r, n);
            }
            /// <summary>
            /// Outputs an grouped decimal string with exponent into Image, with specified fraction size size, and of requested field size.
            /// </summary>
            /// <param name="i">Integer value to output into Image.</param>
            /// <param name="n">Number of fraction digits to output.</param>
            /// <param name="w">Size of item field.</param>
            public void OutFrac(int i, int n, int w)
            {
                if (w == 0) Field(w).PutFrac(i, n);
                else if (w < 0)
                {
                    Text f;
                    f = Field(-w);
                    f.SetValue(Text.NoText);
                    f.Sub(1, w).PutFrac(i, n);
                }
                else Field(w).PutFrac(i, n);
            }
        }

        /// <summary>
        /// An Object of class DirectFile is used to represent an image-oriented direct file in which
        /// the individual images are adressable by ordinal numbers.
        /// </summary>
        /// <remarks>
        /// The variable LOC contains the current ordinal number. When the file is closed, the value of LOC is set to zero. 
        /// The procedure "location" gives access to the current value of LOC. 
        ///
        /// The variable ENDFILE is true when the file is closed or when an image with location greater 
        /// than "lastloc" has been input (through "inimage"). It is set after each "inimage" statement. 
        /// The procedure "endfile" returns the current value. 
        ///
        /// The variable MAXLOC indicates the highest permitted value of LOC. 
        /// On some systems this value corresponds to the size of a preallocated file while, 
        /// on other systems which allow the file to be dynamically extended, this variable is assigned the value "maxint"-1.
        /// </remarks>
        public class DirectFile : ImageFile
        {
            /// <summary>The external file that this object is associated with.</summary>
            protected FileStream file = null;
            protected StreamWriter writer = null;
            protected StreamReader reader = null;

            /// <summary>The variable LOC contains the current ordinal number.</summary>
            private int LOC = 0;

            /// <summary>The variable MAXLOC indicates the highest permitted value of LOC.</summary>
            private int MAXLOC = Int32.MaxValue - 1;

            /// <summary>
            /// The variable ENDFILE is true when the file is closed or when an image with location greater 
            /// than "lastloc" has been input (through "inimage").
            /// </summary>
            private bool ENDFILE = true;

            /// <summary>
            /// The variable "LOCKED" indicates whether the file is currently locked by the executing program. 
            /// The procedure "locked" returns the current value. 
            /// </summary>
            private bool LOCKED = false;

            #region protected members
            /// <summary>
            /// Opens a stream to the external file this object is associated using the appropriate access modes. 
            /// </summary>
            /// <returns>The opened stream to the external file.</returns>
            protected override Stream OpenStreamImpl()
            {
                string fileName = this.FileName().ToString();

                //File access is  applicable to direct-files.
                FileAccess fileaccess;
                if (this.READ && this.WRITE) fileaccess = FileAccess.ReadWrite;
                else if (this.WRITE) fileaccess = FileAccess.Write;
                else fileaccess = FileAccess.Read;

                //shared mode is applicable to direct-files.
                FileShare fileshare;
                if (this.SHARED) fileshare = FileShare.ReadWrite;
                else fileshare = FileShare.None;

                //create mode is applicable to direct-files.
                //append mode is applicable to direct-files.
                FileMode filemode;
                if (this.APPEND)
                {
                    if (this.ANY) filemode = FileMode.Append;
                    else if (this.CREATE) filemode = FileMode.CreateNew;
                    else filemode = FileMode.Open; //we must seek to end of file after opening in this case.
                }
                else
                {
                    if (this.ANY) filemode = FileMode.Create;
                    else if (this.CREATE) filemode = FileMode.CreateNew;
                    else filemode = filemode = FileMode.Truncate;
                }

                this.file = System.IO.File.Open(fileName, filemode, fileaccess, fileshare);
                this.writer = new StreamWriter(file);
                this.reader = new StreamReader(file);
                return this.file;
            }

            /// <summary>
            /// CloseStreamImpl is abstract and must be implemented by File subclass implementers.
            /// It dissolves s the association with an external file. (I.e. closes the stream to the file).
            /// </summary>
            protected override void CloseStreamImpl()
            {
                this.file.Flush();
                this.file.Close();
                this.file = null;
                this.writer = null;
                this.reader = null;
            }
            #endregion

            /// <summary>
            /// Creates a new DirectFile object.
            /// </summary>
            /// <remarks>
            /// The default access mode flags for InFile objects is READWRITE.
            /// </remarks>
            /// <param name="filename">The name of the external file to assosiate with this object.</param>
            public DirectFile(Text filename) : base(filename) 
            {
                this.READ = true;
                this.WRITE = true;
            }

            /// <summary>
            /// Returns the current ordinal image location withing the external file.
            /// </summary>
            /// <returns>The current ordinal image location.</returns>
            public int Location()
            {
                return this.LOC;
            }
            /// <summary>
            /// Returns a flag indicating if end-of-file is reached, or file is closed.
            /// </summary>
            /// <returns>True if end-of-file is reached, or file is closed.</returns>
            public bool EndFile()
            {
                return this.ENDFILE;
            }
            /// <summary>
            /// The variable "LOCKED" indicates whether the file is currently locked by the executing program. 
            /// The procedure "locked" returns the current value. 
            /// </summary>
            /// <returns>True if file is locked, otherwise false.</returns>
            public bool Locked()
            {
                return this.LOCKED;
            }

            /// <summary>
            /// Assosiates the file object with an external file and opens the file.
            /// Returns true upon success.
            /// </summary>
            /// <param name="fileimage">The text frame to use as a buffer.</param>
            /// <returns>True if open succeeds, otherwise false.</returns>
            public bool Open(Text fileimage)
            {
                if (OpenFile())
                {
                    this.Image = fileimage;
                    SetPos(1);
                    Locate(1);
                    this.OPEN = true;
                }
                return OPEN;
            }

            /// <summary>
            /// Procedure "close" causes closing actions on the external file, as specified by the access modes. 
            /// In addition, the association between the file object and the external file is dissolved. 
            /// If possible, the external file is closed.
            /// Returns true upon success.
            /// </summary>
            /// <returns>true if close succeeds, otherwise false.</returns>
            public override bool Close()
            {
                if (CloseFile())
                {
                    this.Image = Text.NoText;
                    if (this.LOCKED) UnLock();
                    this.LOC = 0;
                    this.MAXLOC = 0;

                    this.OPEN = false;
                    this.ENDFILE = true;
                }
                return this.ENDFILE;
            }

            /// <summary>
            /// The procedure "lastloc" indicates the largest location of any written image. 
            /// For a new file the value returned is zero. 
            /// </summary>
            /// <returns>The largest location of any written image.</returns>
            public int LastLoc()
            {
                return (int)(this.file.Length / this.Image.Length());
            }

            /// <summary>
            /// Returns the largest ordinal image loation that the file supports.
            /// </summary>
            /// <returns>The largest ordinal image loation that the file supports.</returns>
            public int MaxLoc()
            {
                return this.MAXLOC;
            }

            /// <summary>
            /// Procedure "locate" may be used to assign a given value to the variable LOC. 
            /// </summary>
            /// <remarks>
            /// This assignment may be accompanied by implementation-defined checks and (possibly asynchronous) instructions 
            /// to an external memory device associated with the file; no transfer to/from "image" is, however, performed. 
            /// A parameter to "locate" less than one or greater than MAXLOC constitutes a run-time error. 
            /// </remarks>
            /// <param name="i">The ordinal number of the image to locate.</param>
            public void Locate(int i)
            {
                if (i < 1 || i > MAXLOC) Error("Locate: Parameter out of range.");
                this.LOC = i;
            }

            /// <summary>
            /// The procedure "inimage" transfers into the text "image" a copy of the external image as currently identified by the variable LOC.
            /// </summary>
            /// If the file does not contain an image with an ordinal number equal to the value of LOC,
            /// the effect of the procedure "inimage" is as follows. If the location indicated is greater than "lastloc",
            /// then ENDFILE is set to true and the end of file text ("!25!") is assigned to "image". 
            /// Otherwise, if the image is a non-written image but there exists at least one written image whose LOC is 
            /// greater than current LOC, then the "image" is filled with NUL ('!0!') characters and the position indicator is 
            /// set to "length"+1 (i.e. "more" becomes false). 
            /// Finally the value of LOC is incremented by one through a "locate" call. 
            public void InImage()
            {
                if (!OPEN) Error("InImage: file closed.");

                SetPos(1);
                ENDFILE = LOC > LastLoc();
                if (ENDFILE)
                {
                    Image.OBJ.MAIN[Image.START - 1] = (char)25;
                }
                else
                {
                    SetFilePosition();
                    int v = file.ReadByte();
                    if (v != 0)
                    {
                        SetFilePosition();
                        //transfer expternal file into image
                        string buf;
                        int i = 0;
                        buf = reader.ReadLine();
                        if (buf != null)
                        {
                            i = buf.Length;

                            //if image is too small then Error("file is to big for image");
                            if (i > this.Image.LENGTH) Error("InImage: Buffer is too short to hold the input image");

                            //blank image;
                            Image.SetValue(Text.NoText); 
                            buf.CopyTo(0, Image.OBJ.MAIN, Image.START - 1, i);
                        }
                    }
                    // non-written image found.
                    else
                    {
                        while (More()) Image.PutChar((char)0);
                    }
                }
                Locate(LOC+1);

            }

            private int GetRecordSize()
            {
                return this.Image.LENGTH + this.writer.NewLine.Length;
            }

            private void SetFilePosition()
            {
                file.Position = (LOC - 1) * GetRecordSize();
            }

            /// <summary>
            /// The procedure "outimage" transfers a copy of the text value "image" to the external image, 
            /// thereby storing in the file an external image whose ordinal number is equal to the current value of LOC. 
            /// If the file contains another image with the same ordinal number, that image is overwritten. 
            /// The value of LOC is then incremented by one through a "locate" call. 
            /// </summary>
            public void OutImage()
            {
                if (!this.OPEN) Error("OutImage: file closed.");
                if (this.LOC > this.MAXLOC) Error("OutImage: file overflow.");

                SetFilePosition();

                writer.WriteLine(Image.OBJ.MAIN, Image.START - 1, Image.LENGTH);
                writer.Flush();
                this.Locate(this.LOC + 1);
                this.Image.SetValue(Text.NoText);
                this.SetPos(1);
            }

            /// <summary>
            /// DeleteImage deletes the image at the current ordinal location, by writing 0 values into the record, possibly truncating the file.
            /// </summary>
            /// <remarks>
            /// The Boolean procedure "deleteimage" makes the image identified by the current value of LOC effectively un-written. 
            /// Irrespective of any physical differences on the external medium between never-written images and deleted ones, 
            /// there is no difference from the program's point of view.
            /// Note that this means that "deleteimage" may decrement the value returned by "lastloc" (in case LOC was equal to "lastloc"). 
            ///
            ///  Note: Outputting a NUL-filled image at location "lastloc" in the file does not necessarily decrement 
            ///  the "lastloc" value; explicit writing (outimage) of such images should be avoided. 
            /// </remarks>
            /// <returns></returns>
            public bool DeleteImage()
            {
                bool success = false;
                if (OPEN)
                {
                    //if we are on last record, then truncate the file.
                    if (LOC == LastLoc()) file.SetLength((LOC) * GetRecordSize() - 1);
                    else
                    {
                        SetFilePosition();
                        for (int i = 0; i < GetRecordSize(); i++) writer.Write((char)0);
                    }
                    success = true;
                    Locate(LOC + 1);
                }
                return success;
            }

            /// <summary>
            /// Returns the next character from Image.
            /// </summary>
            /// <remarks>Note: Inchar skips all unwritten images.</remarks>
            /// <returns>A character from Image.</returns>
            public char InChar()
            {
                while (!More()) InImage();
                return Image.GetChar();
            }

            /// <summary>
            /// Procedure "lock" enables the program to get exclusive access to all or part of the file. 
            /// The effect of a "lock" call while the file is locked ("LOCKED" is true) is that the previous lock 
            /// is immediately released (prior to the new locking attempt). 
            /// </summary>
            /// <remarks>
            /// The parameter "timelimit" is the (clock) time in seconds that is the maximum waiting time for the resource. 
            /// If "timelimit" is less than or equal to zero, the procedure returns immediately without performing any actions upon the file. 
            ///
            /// The parameters "loc1" and "loc2" identify the part of the file to be locked, by giving the ordinal numbers 
            /// of two external images (bytes). The program is given exclusive access to a part of the file which includes 
            /// the requested region. If the two parameters are both zero, this implies locking the whole file. 
            /// Otherwise, the size of the part of the file that is actually locked, is implementation-dependent; 
            /// it may even include the entire file. 
            ///
            /// A return value of zero indicates a successful "lock" operation. The value -1 indicates that "timelimit" was exceeded
            /// (or was zero or negative). 
            /// A negative value less than -1 indicates "lock" failure and its interpretation is implementation-defined. 
            /// </remarks>
            /// <param name="timelimit">The (clock) time in seconds that is the maximum waiting time for the resource.</param>
            /// <param name="loc1"></param>
            /// <param name="loc2"></param>
            /// <returns></returns>
            public int Lock(Single timelimit, int loc1, int loc2)
            {
                int retval = -1;

                //TODO: we ignore the timelimit for now.

                if (this.LOCKED) UnLock();
                long offset = (loc1 - 1) * this.GetRecordSize();
                long size = (loc2 - loc1) * this.GetRecordSize();
                this.file.Lock(offset, size);
                this.LOCKED = true;
                retval = 0;

                return retval;
            }

            /// <summary>
            /// The Boolean procedure "unlock" eliminates the effect of any preceding "lock" call. The Boolean procedure "checkpoint" is called initially. 
            /// The returned value is that returned by the "checkpoint" call. 
            /// </summary>
            /// <returns>Value of CheckPoint before unlock.</returns>
            public bool UnLock()
            {
                bool retval = CheckPoint();
                if (this.LOCKED)
                {
                    this.file.Unlock(0, this.file.Length);
                    this.LOCKED = false;
                }
                return retval;
            }

            /// <summary>
            /// All files producing output (sequential output or direct files) contain a Boolean procedure "checkpoint". 
            /// The procedure causes the environment to attempt to secure the output produced so far. 
            /// Depending on the nature of the associated external device, this causes completion of output transfer 
            /// (i.e. intermediate buffer contents are transferred). 
            /// If this is not possible or meaningful, "checkpoint" is a dummy operation in which case the value false is returned. 
            /// </summary>
            /// <returns>True on success.</returns>
            public bool CheckPoint()
            {
                this.file.Flush();
                return true;
            }

            /// <summary>
            /// Scans the external file for more charaters. Skips ahead until non space non tab character is found.
            /// Returns true of no more characters is found in file.
            /// </summary>
            /// <remarks>
            /// The purpose of the procedure "lastitem" is to skip past all SP and HT characters (ISOrank 32 and 9 respectively). 
            /// The process of scanning may involve the transfer of several successive external images. 
            /// If the file contains no further non-space, non-tab characters the value true is returned. 
            ///</remarks>
            /// <returns>True if there are no more characters is the file.</returns>
            public bool LastItem()
            {
                char c;
                c = ' ';
                while (!ENDFILE && (c == ' ' || c == '\t')) c = InChar();
                if (c != ' ') SetPos(Pos() - 1);
                return ENDFILE;
            }

            /// <summary>
            /// Returns a new image (text frame) containing the next 'w' characters in the external file.
            /// </summary>
            /// <remarks>
            /// The expression "intext(w)" where "w" is a positive integer is a reference to a new alterable main frame of length w 
            /// containing a copy of the next w characters of the file. POS is set to the following character. 
            /// The expression "intext(0)" references notext. In contrast to the item-oriented procedures (see below), 
            /// "intext" operates on a continuous stream of characters, reading several images if necessary. 
            /// 
            /// Note: The result may be a reference to an "EOF-image" (cf. 10.4.2). 
            ///</remarks>
            /// <param name="w">Number of characters to read from stream.</param>
            /// <returns>New image containing the next 'w' charaters from external file.</returns>
            public Text InText(int w)
            {
                Text t;
                t = _outer.Blanks(w);
                while (t.More()) t.PutChar(InChar());
                return t;
            }
            /// <summary>
            /// Converts the string representation of a number in the Image to an integer,
            /// starting from current possition. 
            /// </summary>
            /// <returns>An integer value converted from the Image.</returns>
            public int InInt()
            {
                if (LastItem()) Error("InInt: End of file");
                Text t;
                t = Image.Sub(Pos(), Length() - Pos() + 1);
                int i = t.GetInt();
                SetPos(Pos() + t.Pos() - 1);
                return i;
            }
            /// <summary>
            /// Converts the string representation of a number in the Image to a long real (Double),
            /// starting from current possition. 
            /// </summary>
            /// <returns>A long real value converted from the Image.</returns>
            public double InReal()
            {
                if (LastItem()) Error("InReal: End of file");
                Text t;
                t = Image.Sub(Pos(), Length() - Pos() + 1);
                double d = t.GetReal();
                SetPos(Pos() + t.Pos() - 1);
                return d;
            }
            /// <summary>
            /// Converts the string representation of a grouped number item in the Image to an integer,
            /// starting from current possition. 
            /// </summary>
            /// <returns>An integer value converted from the Image.</returns>
            public int InFrac()
            {
                if (LastItem()) Error("InReal: End of file");
                Text t;
                t = Image.Sub(Pos(), Length() - Pos() + 1);
                int i = t.GetFrac();
                SetPos(Pos() + t.Pos() - 1);
                return i;
            }

            /// <summary>
            /// The procedure "outchar" stores a character in the POS position of "image". 
            /// If "more" is false, "outimage" is called first. 
            /// </summary>
            /// <param name="c">The character to write to text frame buffer.</param>
            public void OutChar(char c)
            {
                if (!More()) OutImage();
                Image.PutChar(c);
            }

            /// <summary>
            /// Procedure "outtext" always transfers the complete contents of the text parameter to the text frame buffer. 
            /// </summary>
            /// <param name="t">The text to transfer to the text frame buffer.</param>
            public void OutText(Text t)
            {
                if ((Pos() > 1) && (t.Length() > Length() - Pos() + 1)) OutImage();
                t.SetPos(1);
                while (t.More()) OutChar(t.GetChar());
            }

            /// <summary>
            /// Field is an internal "handy" method creating a sub frame, inside the Image text frame, of the requested size.
            /// Field is used by the item oriented editing procedures of class OutImage.
            /// </summary>
            /// <remarks>
            /// Each item is edited into a "field" (subtext of "image") normally starting at the current accessible character. 
            /// POS is advanced correspondingly. 
            /// If the remainder of "image" is too short to contain the item, "outimage" is called implicitly prior to the editing operation. 
            /// The field is space-filled before the editing operation (inside the editing procedures). 
            /// 
            /// A run-time error occurs if a field cannot be contained within the full length of "image". 
            ///
            /// Parameter "w" determines both the length of this field and the adjustment of the item within it, as follows. 
            ///
            ///     w > 0    The field length is w, the item is right-adjusted.
            ///
            ///     w < 0    The field length is abs(w), the item is left-adjusted.
            ///
            ///     w = 0    The field length is the exact number of characters needed
            ///              to contain the item (i.e. no leading or trailing spaces).
            /// </remarks>
            /// <param name="w">Size of sub frame to create.</param>
            /// <returns>A sub frame inside Image.</returns>
            private Text Field(int w)
            {
                if (w > Length()) Error("Field: Item too long");

                if ((Pos() + w - 1) > Length()) OutImage();

                Text F = Image.Sub(Pos(), w);
                SetPos(Pos() + w);
                return F;
            }

            /// <summary>
            /// Outputs an Integer into Image of requested field size.
            /// </summary>
            /// <param name="i">Integer item to output into Image.</param>
            /// <param name="w">Size of item field.</param>
            public void OutInt(int i, int w)
            {
                if (w == 0) Field(w).PutInt(i);
                else if (w < 0)
                {
                    Text f;
                    f = Field(-w);
                    f.SetValue(Text.NoText);
                    f.Sub(1, w).PutInt(i);
                }
                else Field(w).PutInt(i);
            }
            /// <summary>
            /// Outputs a decimal number into Image, with specified fraction size and of requested field size.
            /// </summary>
            /// <param name="r">Long real value to output into Image.</param>
            /// <param name="n">Number of fraction digits.</param>
            /// <param name="w">Size of item field.</param>
            public void OutFix(double r, int n, int w)
            {
                if (w == 0) Field(w).PutFix(r, n);
                else if (w < 0)
                {
                    Text f;
                    f = Field(-w);
                    f.SetValue(Text.NoText);
                    f.Sub(1, w).PutFix(r, n);
                }
                else Field(w).PutFix(r, n);
            }
            /// <summary>
            /// Outputs an long real number with exponent into Image, with specified exponent size, and of requested field size.
            /// </summary>
            /// <param name="r">Long real number to output into Image.</param>
            /// <param name="n">Number of exponent part digits.</param>
            /// <param name="w">Size of item field.</param>
            public void OutReal(double r, int n, int w)
            {
                if (w == 0) Field(w).PutReal(r, n);
                else if (w < 0)
                {
                    Text f;
                    f = Field(-w);
                    f.SetValue(Text.NoText);
                    f.Sub(1, w).PutReal(r, n);
                }
                else Field(w).PutReal(r, n);
            }
            /// <summary>
            /// Outputs an grouped decimal string with exponent into Image, with specified fraction size size, and of requested field size.
            /// </summary>
            /// <param name="i">Integer value to output into Image.</param>
            /// <param name="n">Number of fraction digits to output.</param>
            /// <param name="w">Size of item field.</param>
            public void OutFrac(int i, int n, int w)
            {
                if (w == 0) Field(w).PutFrac(i, n);
                else if (w < 0)
                {
                    Text f;
                    f = Field(-w);
                    f.SetValue(Text.NoText);
                    f.Sub(1, w).PutFrac(i, n);
                }
                else Field(w).PutFrac(i, n);
            }
        }

        /// <summary>
        /// The class "printfile" defines a class for line printer oriented output. 
        /// </summary>
        /// <remarks>
        /// An object of the class "printfile" is used to represent a line printer oriented output file. 
        /// The class is a subclass of "outfile". A file image normally represents a line on a printed page. 
        /// </remarks>
        public class PrintFile : OutFile
        {
            /// <summary>The variable LINE indicates the ordinal number of the next line to be printed (on the current page), 
            /// provided that no implicit or explicit "eject" statement occurs.</summary>
            private int LINE;
            /// <summary>The variable LINES_PER_PAGE indicates the maximum number of physical lines that may be printed on each page, 
            /// including intervening blank lines</summary>
            private int LINES_PER_PAGE;
            /// <summary>The variable SPACING represents the value by which the variable LINE is incremented after the next printing operation</summary>
            private int SPACING;
            /// <summary>The variable PAGE indicates the ordinal number of the current page.</summary>
            private int PAGE;

            private int DEFAULT_LPP = 60;
            /// <summary>
            /// Creates a new PrintFile instance.
            /// </summary>
            /// <remarks>
            /// The default access mode flags for PrintFile objects is CreateAny.
            /// </remarks>
            /// <param name="filename">The name of the external file to assosiate with this object.</param>
            public PrintFile(Text filename)
                : base(filename)
            {
                this.SPACING = 1;
                this.LINES_PER_PAGE = DEFAULT_LPP;
                this.LINE = 0;
                this.PAGE = 0;
            }

            /// <summary>
            /// Returns the current ordinal line number in the current page, for the next line to be printed.
            /// </summary>
            /// <returns>The current ordinal line number in the current page.</returns>
            public int Line() { return this.LINE; }
            /// <summary>
            /// Returns the current ordinal page number.
            /// </summary>
            /// <returns>The current ordinal page number.</returns>
            public int Page() { return this.PAGE; }
            /// <summary>
            /// Assosiates the file object with an external file and opens the file.
            /// Returns true upon success.
            /// </summary>
            /// <param name="fileimage">The text frame to use as a buffer.</param>
            /// <returns>>True if open succeeds, otherwise false.</returns>
            public override bool Open(Text fileimage)
            {
                if (base.Open(fileimage))
                {
                    Image = fileimage;
                    PAGE = 0;
                    LINE = 1;
                    SetPos(1);
                    //Eject(1); //TODO: this seams to not be implemented in cim. Verify what is correct.


                    if (_stdOut) this.DEFAULT_LPP = int.MaxValue;
                    this.LinesPerPage(0);

                    OPEN = true;
                }
                return OPEN;
            }
            /// <summary>
            /// Procedure "close" causes closing actions on the external file, as specified by the access modes. 
            /// In addition, the association between the file object and the external file is dissolved. 
            /// If possible, the external file is closed.
            /// Returns true upon success.
            /// </summary>
            /// <remarks>The procedure "close" calls "outimage" if the position indicator is not equal to 1.</remarks>
            /// <returns>true if close succeeds, otherwise false.</returns>
            public override bool Close()
            {
                if (Pos() != 1) OutImage();
                
                //TODO: Eject according to simul spec. But we ignore for now since this obviously do not
                //apply to stdout that we only support for now.
                if (!_stdOut) Eject(LINES_PER_PAGE);
                if (base.Close())
                {
                    LINE = 0;
                    SPACING = 1;
                    LINES_PER_PAGE = DEFAULT_LPP;
                    Image = Text.NoText;
                    OPEN = false;
                }
                return !OPEN;
            }
            /// <summary>
            /// LinesPerPage sets a new value of lines per page, and returns the orignal value before the change.
            /// </summary>
            /// <remarks>
            /// If the parameter to "linesperpage" is zero, LINES_PER_PAGE is reset to the original value (assigned at object generation).
            /// A parameter value less than zero may be used to indicate an "infinite" value of LINES_PER_PAGE, 
            /// thus avoiding any automatic calls on "eject".
            /// </remarks>
            /// <param name="n">New lines per page value.</param>
            /// <returns>The original value before the change.</returns>
            public int LinesPerPage(int n)
            {
                int original = this.LINES_PER_PAGE;
                if (n > 0) this.LINES_PER_PAGE = n;
                else if (n < 0) this.LINES_PER_PAGE = int.MaxValue;
                else this.LINES_PER_PAGE = DEFAULT_LPP;
                return original;
            }
            /// <summary>
            /// Sets the number of lines to increment after each printing operation.
            /// </summary>
            /// <remarks>
            /// The variable SPACING represents the value by which the variable LINE is incremented after the next 
            /// printing operation. Its value may be changed by the procedure "spacing". A call on the 
            /// procedure "spacing" with a parameter less than zero or greater than LINES_PER_PAGE constitutes an error. 
            /// The effect of a a parameter to "spacing" which is equal to zero may be defined as forcing 
            /// successive printing operations on the same physical line. Note, however, that on some physical media 
            /// this may not be possible, in which case spacing(0) has the same effect as spacing(1) 
            /// (i.e. no overprinting). 
            ///</remarks>
            /// <param name="n">Number of lines to increment after each printing operation.</param>
            public void Spacing(int n)
            {
                if (n < 0 || n > this.LINES_PER_PAGE)
                    Error("Spacing: Parameter out of range");
                if (n == 0) n = 1;
                this.SPACING = n;
            }
            /// <summary>
            /// The procedure "eject" is used to position to a certain line identified by the parameter, 'n'.
            /// </summary>
            /// <remarks>
            /// The variable "PAGE" is incremented by one each time an explicit or implicit "eject" implies a new page. 
            ///
            ///    The following cases can be distinguished: 
            ///
            ///         n &lt;= 0                 : ERROR
            ///         n >  LINES_PER_PAGE    : Equivalent to eject (1)
            ///         n &lt;= LINE              : Position to line number n on the next page
            ///         n >  LINE              : Position to line number n on the current page
            ///
            ///    The tests above are performed in the given sequence. 
            /// </remarks>
            /// <param name="n"></param>
            public void Eject(int n)
            {
                if (this.LINES_PER_PAGE < int.MaxValue)
                {
                    if (!OPEN) Error("Eject: file closed.");
                    if (n <= 0) Error("Eject: Parameter out of range.");
                    if (n > this.LINES_PER_PAGE) n = 1;

                    if (n <= this.LINE)
                    {
                        this.writer.Write((char)12); //Formfeed
                        PAGE++;
                        LINE = 1;
                    }
                    while (LINE < n)
                    {
                        writer.WriteLine();
                        LINE++;
                    }
                }
            }
            /// <summary>
            /// OutImage transfers the contents of the Image buffer to the external file.
            /// </summary>
            /// <remarks>
            /// The transfer of an image from the text "image" to the file is performed by the procedure "outimage". 
            /// The procedure reacts in an implementation-defined way if the "image" length is not appropriate for 
            /// the external file. 
            /// (Depending on file type and host system, the external file does not necessarily record trailing blanks 
            /// from the "image".) 
            /// After the transfer, "image" is cleared to blanks and the position indicator is set to 1.
            /// In addition LINE is updated, and possible PAGE.
            /// </remarks>
            public override void OutImage()
            {
                if (!OPEN) Error("OutImage: file closed.");

                if (this.LINE > this.LINES_PER_PAGE) Eject(1);

                //output the image on the line indicated by LINE
                base.OutImage();

                for (int n = 1; n < SPACING; n++) writer.WriteLine();
                this.LINE += this.SPACING;
                Image.SetValue(Text.NoText);
                SetPos(1);
            }
            /// <summary>
            /// The procedure "outrecord" transfers to the file only that part of "image" which precedes POS. 
            /// The contents are not blanked after the transfer, although POS is set to one. 
            /// </summary>
            public override void OutRecord()
            {
                if (!OPEN) Error("OutRecrd: file closed.");

                if (this.LINE > this.LINES_PER_PAGE) Eject(1);

                //output image.Sub(1, Pos()-1) on the line indicated by LINE;
                base.OutRecord();

                for (int n = 1; n < SPACING; n++) writer.WriteLine();
                this.LINE += this.SPACING;
                SetPos(1);
            }
        }

        /// <summary>
        /// The class bytefile is the common prefix class for all byte-oriented files. 
        /// </summary>
        /// <remarks>
        /// Bytefiles read and write files as continuous streams of bytes.
        /// </remarks>
        public abstract class ByteFile : File
        {
            public ByteFile(Text filename) : base(filename) { }

            /// <summary>
            /// Returns the size of bytes in bytefiles.
            /// </summary>
            /// <remarks>
            /// The variable BYTESIZE defines the range of the byte values transferred. 
            /// Byte values are integers in the range (0:2**BYTESIZE-1). 
            /// The BYTESIZE value of the file object is accessible through procedure "bytesize". 
            ///
            /// Note: "Bytesize" returns zero before first "open" of the bytefile. 
            //</remarks>
            /// <returns>The size of bytes in bytefiles.</returns>
            public short ByteSize()
            {
                if (OPEN) return this.BYTESIZE;
                else return 0;
            }

        }
        
        /// <summary>
        /// An object of the class "inbytefile" is used to represent a byte-oriented sequential input file. 
        /// </summary>
        public class InByteFile : ByteFile
        {
            /// <summary>A reader surrounding the current file stream.</summary>
            protected BinaryReader reader = null;

            /// <summary>
            /// ENDFILE is true if the file is closed or the external file is at end-of-file
            /// </summary>
            private bool ENDFILE = true;

            #region protected members
            /// <summary>
            /// Opens a stream to the external file this object is associated using the appropriate access modes. 
            /// </summary>
            /// <returns>The opened stream to the external file.</returns>
            protected override Stream OpenStreamImpl()
            {
                string fileName = this.FileName().ToString();
                Stream s;

                //create mode is not applicable to in-files
                //append mode is not applicable to in-files.
                FileMode filemode = FileMode.Open;

                //shared mode is applicable to in-files
                FileShare fileshare;
                if (this.SHARED) fileshare = FileShare.ReadWrite;
                else fileshare = FileShare.None;

                //File access is not applicable to in-files.
                FileAccess fileaccess = FileAccess.Read;

                s = System.IO.File.Open(fileName, filemode, fileaccess, fileshare);

                this.reader = new BinaryReader(s);
                return this.reader.BaseStream;
            }

            /// <summary>
            /// CloseStreamImpl is abstract and must be implemented by File subclass implementers.
            /// It dissolves s the association with an external file. (I.e. closes the stream to the file).
            /// </summary>
            protected override void CloseStreamImpl()
            {
                this.reader.Close();
                this.reader = null;
            }
            #endregion

            #region public members
            /// <summary>
            /// Creates a new InByteFile object.
            /// </summary>
            /// <remarks>
            /// The default access mode flags for InByteFile objects is SHARED.
            /// </remarks>
            /// <param name="filename">The name of the external file to assosiate with this object.</param>
            public InByteFile(Text filename) : base(filename)
            {
                this.SHARED = true;
            }
            /// <summary>
            /// Returns a flag indicating if end-of-file is reached, or file is closed.
            /// </summary>
            /// <returns>True if end-of-file is reached, or file is closed.</returns>
            public bool EndFile()
            {
                return this.ENDFILE;
            }
            /// <summary>
            /// Assosiates the file object with an external file and opens the file.
            /// Returns true upon success.
            /// </summary>
            /// <returns>True if open succeeds, otherwise false.</returns>
            public bool Open()
            {
                if (OpenFile())
                {
                    ENDFILE = false;
                    this.OPEN = true;
                }
                return OPEN;
            }
            /// <summary>
            /// Procedure "close" causes closing actions on the external file, as specified by the access modes. 
            /// In addition, the association between the file object and the external file is dissolved. 
            /// If possible, the external file is closed.
            /// Returns true upon success.
            /// </summary>
            /// <returns>true if close succeeds, otherwise false.</returns>
            public override bool Close()
            {
                if (CloseFile())
                {
                    OPEN = false;
                    ENDFILE = true;
                }
                return ENDFILE;
            }
            /// <summary>
            /// The procedure "inbyte" returns the short integer value corresponding to the input byte.
            /// </summary>
            /// <remarks>
            ///  If there are no more bytes to read, a zero result is returned. 
            ///  If prior to an "inbyte" call ENDFILE is true, a run-time error occurs. </remarks>
            /// <returns></returns>
            public short InByte()
            {
                if (ENDFILE) Error("InByte: End of file.");

                byte data;

                try
                {
                    data = reader.ReadByte();
                }
                catch (EndOfStreamException)
                {
                    ENDFILE = true;
                    data = 0;
                }
                return data;
            }
            /// <summary>
            /// The procedure "intext" fills the frame of the parameter "t" with successive input bytes. 
            /// </summary>
            /// <param name="t">The text frame to fill with bytes.</param>
            /// <returns>A text frame filled with bytes read from file</returns>
            public Text InText(Text t)
            {
                t.SetPos(1);
                while (t.More() && !ENDFILE) t.PutChar(_outer.Char(InByte()));
                if (ENDFILE) t.SetPos(t.Pos()-1);
                return t.Sub(1, t.Pos()-1);
            }
            #endregion
        }

        /// <summary>
        /// An object of the class "outbytefile" is used to represent a sequential output file of bytes. 
        /// </summary>
        public class OutByteFile : ByteFile
        {
            /// <summary>A writer surrounding the current file stream.</summary>
            protected BinaryWriter writer = null;

            #region protected members
            /// <summary>
            /// Opens a stream to the external file this object is associated using the appropriate access modes. 
            /// </summary>
            /// <returns>The opened stream to the external file.</returns>
            protected override Stream OpenStreamImpl()
            {
                Stream s;
                string fileName = this.FileName().ToString();

                s = System.IO.File.OpenWrite(fileName);

                this.writer = new BinaryWriter(s);
                return this.writer.BaseStream;
            }

            /// <summary>
            /// CloseStreamImpl is abstract and must be implemented by File subclass implementers.
            /// It dissolves s the association with an external file. (I.e. closes the stream to the file).
            /// </summary>
            protected override void CloseStreamImpl()
            {
                this.writer.Flush();
                this.writer.Close();
                this.writer = null;
            }
            #endregion

            /// <summary>
            /// Creates a new OutByteFile instance.
            /// </summary>
            /// <remarks>
            /// The default access mode flags for OutByteFile objects is CreateAny.
            /// </remarks>
            /// <param name="filename">The name of the external file to assosiate with this object.</param>
            public OutByteFile(Text filename) : base(filename) 
            {
                this.ANY = true;
            }

            /// <summary>
            /// Assosiates the file object with an external file and opens the file.
            /// Returns true upon success.
            /// </summary>
            /// <returns>>True if open succeeds, otherwise false.</returns>
            public virtual bool Open()
            {
                if (OpenFile())
                {
                    OPEN = true;
                }
                return OPEN;
            }

            /// <summary>
            /// Procedure "close" causes closing actions on the external file, as specified by the access modes. 
            /// In addition, the association between the file object and the external file is dissolved. 
            /// If possible, the external file is closed.
            /// Returns true upon success.
            /// </summary>
            /// <remarks>The procedure "close" calls "outimage" if the position indicator is not equal to 1.</remarks>
            /// <returns>true if close succeeds, otherwise false.</returns>
            public override bool Close()
            {
                if (CloseFile())
                {
                    this.OPEN = false;
                }
                return !OPEN;
            }

            /// <summary>
            /// The procedure "outbyte" outputs a byte corresponding to the parameter value.
            /// </summary>
            /// <remarks>
            /// If the parameter value is less than zero or exceeds the maximum permitted value, 
            /// as defined by BYTESIZE, a run-time error occurs. 
            /// If the file is not open, a run-time error occurs. 
            /// </remarks>
            /// <param name="x"></param>
            public void OutByte(short x)
            {
                if (!OPEN) Error("OutByte: file closed.");
                if (x < 0 || x >= Math.Pow(2, BYTESIZE)) Error("OutByte: illegal byte value.");

                this.writer.Write((byte) x);
                this.writer.Flush();
            }
            /// <summary>
            /// The procedure "outtext" outputs all characters in the parameter "t" as bytes. 
            /// </summary>
            /// <param name="t"></param>
            public void OutText(Text t)
            {
                t.SetPos(1);
                while (t.More()) OutByte((short) _outer.Rank(t.GetChar()));
            }
        }
        /// <summary>
        /// The class "directbytefile" defines a byte-oriented direct file. 
        /// </summary>
        /// <remarks>
        /// An object of the class "directbytefile" is used to represent an external file in which the individual bytes 
        /// are addressable by ordinal numbers. The variable LOC is defined to represent such ordinal numbers. 
        /// When the file is closed, the value of LOC is zero. 
        ///
        /// The variable MAXLOC indicates the maximum possible location on the external file. 
        /// If this is not meaningful MAXLOC has the value of "maxint"-1. 
        /// The procedure "maxloc" gives access to the current MAXLOC value. 
        ///
        /// The procedure "endfile" returns true whenever LOC indicates an address greater than "lastloc". 
        ///
        /// The procedures "intext" and "outtext" conform to the pattern for "inbytefile" and "outbytefile", respectively. 
        /// </remarks>
        public class DirectByteFile : ByteFile
        {
            /// <summary>The external file that this object is associated with.</summary>
            protected FileStream file = null;
            protected BinaryWriter writer = null;
            protected BinaryReader reader = null;

            /// <summary>The variable LOC contains the current ordinal number.</summary>
            private int LOC = 0;

            /// <summary>The variable MAXLOC indicates the highest permitted value of LOC.</summary>
            private int MAXLOC = Int32.MaxValue - 1;

            /// <summary>
            /// The variable ENDFILE is true when the file is closed or when an image with location greater 
            /// than "lastloc" has been input (through "inimage").
            /// </summary>
            private bool ENDFILE = true;

            /// <summary>
            /// The variable "LOCKED" indicates whether the file is currently locked by the executing program. 
            /// The procedure "locked" returns the current value. 
            /// </summary>
            private bool LOCKED = false;

            #region protected members
            /// <summary>
            /// Opens a stream to the external file this object is associated using the appropriate access modes. 
            /// </summary>
            /// <returns>The opened stream to the external file.</returns>
            protected override Stream OpenStreamImpl()
            {
                string fileName = this.FileName().ToString();

                //File access is  applicable to direct-files.
                FileAccess fileaccess;
                if (this.READ && this.WRITE) fileaccess = FileAccess.ReadWrite;
                else if (this.WRITE) fileaccess = FileAccess.Write;
                else fileaccess = FileAccess.Read;

                //shared mode is applicable to direct-files.
                FileShare fileshare;
                if (this.SHARED) fileshare = FileShare.ReadWrite;
                else fileshare = FileShare.None;

                //create mode is applicable to direct-files.
                //append mode is applicable to direct-files.
                FileMode filemode;
                if (this.APPEND)
                {
                    if (this.ANY) filemode = FileMode.Append;
                    else if (this.CREATE) filemode = FileMode.CreateNew;
                    else filemode = FileMode.Open; //we must seek to end of file after opening in this case.
                }
                else
                {
                    if (this.ANY) filemode = FileMode.Create;
                    else if (this.CREATE) filemode = FileMode.CreateNew;
                    else filemode = filemode = FileMode.Truncate;
                }

                this.file = System.IO.File.Open(fileName, filemode, fileaccess, fileshare);
                this.writer = new BinaryWriter(file);
                this.reader = new BinaryReader(file);
                return this.file;
            }

            /// <summary>
            /// CloseStreamImpl is abstract and must be implemented by File subclass implementers.
            /// It dissolves s the association with an external file. (I.e. closes the stream to the file).
            /// </summary>
            protected override void CloseStreamImpl()
            {
                this.file.Flush();
                this.file.Close();
                this.file = null;
                this.writer = null;
                this.reader = null;
            }
            #endregion

            /// <summary>
            /// Creates a new DirectByteFile object.
            /// </summary>
            /// <remarks>
            /// The default access mode flags for DirectByteFile objects is READWRITE.
            /// </remarks>
            /// <param name="filename">The name of the external file to assosiate with this object.</param>
            public DirectByteFile(Text filename) : base(filename) 
            {
                this.READ = true;
                this.WRITE = true;
            }

            /// <summary>
            /// Returns the current ordinal address location withing the external file.
            /// </summary>
            /// <returns>The current ordinal address location.</returns>
            public int Location()
            {
                return this.LOC;
            }
            /// <summary>
            /// Returns a flag indicating if end-of-file is reached, or file is closed.
            /// </summary>
            /// <returns>True if end-of-file is reached, or file is closed.</returns>
            public bool EndFile()
            {
                return this.ENDFILE;
            }
            /// <summary>
            /// The variable "LOCKED" indicates whether the file is currently locked by the executing program. 
            /// The procedure "locked" returns the current value. 
            /// </summary>
            /// <returns>True if file is locked, otherwise false.</returns>
            public bool Locked()
            {
                return this.LOCKED;
            }

            /// <summary>
            /// Returns the largest ordinal address loation that the file supports.
            /// </summary>
            /// <returns>The largest ordinal address loation that the file supports.</returns>
            public int MaxLoc()
            {
                return this.MAXLOC;
            }
            /// <summary>
            /// Assosiates the file object with an external file and opens the file.
            /// Returns true upon success.
            /// </summary>
            /// <returns>True if open succeeds, otherwise false.</returns>
            public bool Open()
            {
                if (OpenFile())
                {
                    Locate(1);
                    ENDFILE = false;
                    this.OPEN = true;
                }
                return OPEN;
            }

            /// <summary>
            /// Procedure "close" causes closing actions on the external file, as specified by the access modes. 
            /// In addition, the association between the file object and the external file is dissolved. 
            /// If possible, the external file is closed.
            /// Returns true upon success.
            /// </summary>
            /// <returns>true if close succeeds, otherwise false.</returns>
            public override bool Close()
            {
                if (CloseFile())
                {
                    if (this.LOCKED) UnLock();
                    this.LOC = 0;
                    this.MAXLOC = 0;

                    this.OPEN = false;
                    this.ENDFILE = true;
                }
                return this.ENDFILE;
            }

            /// <summary>
            /// Procedure "locate" may be used to assign a given value to the variable LOC. 
            /// </summary>
            /// <remarks>
            /// This assignment may be accompanied by implementation-defined checks and (possibly asynchronous) instructions 
            /// to an external memory device associated with the file; no transfer to/from external file, however, performed. 
            /// A parameter to "locate" less than one or greater than MAXLOC constitutes a run-time error. 
            /// </remarks>
            /// <param name="i">The ordinal number of the image to locate.</param>
            public void Locate(int i)
            {
                if (i < 1 || i > MAXLOC) Error("Locate: Parameter out of range.");
                this.LOC = i;
            }

            /// <summary>
            /// The procedure "lastloc" indicates the largest location of any written byte. 
            /// For a new file the value returned is zero. 
            /// </summary>
            /// <returns>The largest location of any written image.</returns>
            public int LastLoc()
            {
                return (int)(this.file.Length / GetRecordSize());
            }

            private int GetRecordSize()
            {
                return 1;
            }

            private void SetFilePosition()
            {
                file.Position = (LOC - 1) * GetRecordSize();
            }

            /// <summary>
            /// The procedure "inbyte" returns the short integer value corresponding to the input byte.
            /// </summary>
            /// <remarks>
            ///  If there are no more bytes to read, a zero result is returned. 
            ///  If prior to an "inbyte" call ENDFILE is true, a run-time error occurs. 
            /// 
            /// The result of "inbyte" from an unwritten LOC is zero 
            /// </remarks>
            /// <returns></returns>
            public short InByte()
            {
                if (ENDFILE) Error("InByte: End of file.");

                byte data;

                ENDFILE = LOC > LastLoc();
                if (ENDFILE)
                {
                    return 0;
                }
                try
                {
                    SetFilePosition();
                    data = reader.ReadByte();
                    LOC++;
                }
                catch (EndOfStreamException)
                {
                    ENDFILE = true;
                    data = 0;
                }
                return data;
            }

            /// <summary>
            /// The procedure "outbyte" outputs a byte corresponding to the parameter value.
            /// </summary>
            /// <remarks>
            /// If the parameter value is less than zero or exceeds the maximum permitted value, 
            /// as defined by BYTESIZE, a run-time error occurs. 
            /// If the file is not open, a run-time error occurs. 
            /// </remarks>
            /// <param name="x"></param>
            public void OutByte(short x)
            {
                if (!OPEN) Error("OutByte: file closed.");
                if (this.LOC > this.MAXLOC) Error("OutByte: file overflow.");
                if (x < 0 || x >= Math.Pow(2, BYTESIZE)) Error("OutByte: illegal byte value.");

                SetFilePosition();
                
                this.writer.Write((byte) x);
                this.writer.Flush();
                LOC++;
            }

            /// <summary>
            /// All files producing output (sequential output or direct files) contain a Boolean procedure "checkpoint". 
            /// The procedure causes the environment to attempt to secure the output produced so far. 
            /// Depending on the nature of the associated external device, this causes completion of output transfer 
            /// (i.e. intermediate buffer contents are transferred). 
            /// If this is not possible or meaningful, "checkpoint" is a dummy operation in which case the value false is returned. 
            /// </summary>
            /// <returns>True on success.</returns>
            public bool CheckPoint()
            {
                this.file.Flush();
                return true;
            }
            /// <summary>
            /// Procedure "lock" enables the program to get exclusive access to all or part of the file. 
            /// The effect of a "lock" call while the file is locked ("LOCKED" is true) is that the previous lock 
            /// is immediately released (prior to the new locking attempt). 
            /// </summary>
            /// <remarks>
            /// The parameter "timelimit" is the (clock) time in seconds that is the maximum waiting time for the resource. 
            /// If "timelimit" is less than or equal to zero, the procedure returns immediately without performing any actions upon the file. 
            ///
            /// The parameters "loc1" and "loc2" identify the part of the file to be locked, by giving the ordinal numbers 
            /// of two external images (bytes). The program is given exclusive access to a part of the file which includes 
            /// the requested region. If the two parameters are both zero, this implies locking the whole file. 
            /// Otherwise, the size of the part of the file that is actually locked, is implementation-dependent; 
            /// it may even include the entire file. 
            ///
            /// A return value of zero indicates a successful "lock" operation. The value -1 indicates that "timelimit" was exceeded
            /// (or was zero or negative). 
            /// A negative value less than -1 indicates "lock" failure and its interpretation is implementation-defined. 
            /// </remarks>
            /// <param name="timelimit">The (clock) time in seconds that is the maximum waiting time for the resource.</param>
            /// <param name="loc1"></param>
            /// <param name="loc2"></param>
            /// <returns></returns>
            public int Lock(Single timelimit, int loc1, int loc2)
            {
                int retval = -1;

                //TODO: we ignore the timelimit for now.

                if (this.LOCKED) UnLock();
                long offset = (loc1 - 1) * GetRecordSize();
                long size = (loc2 - loc1) * GetRecordSize();
                this.file.Lock(offset, size);
                this.LOCKED = true;
                retval = 0;

                return retval;
            }

            /// <summary>
            /// The Boolean procedure "unlock" eliminates the effect of any preceding "lock" call. The Boolean procedure "checkpoint" is called initially. 
            /// The returned value is that returned by the "checkpoint" call. 
            /// </summary>
            /// <returns>Value of CheckPoint before unlock.</returns>
            public bool UnLock()
            {
                bool retval = CheckPoint();
                if (this.LOCKED)
                {
                    this.file.Unlock(0, this.file.Length);
                    this.LOCKED = false;
                }
                return retval;
            }
            /// <summary>
            /// The procedure "intext" fills the frame of the parameter "t" with successive input bytes. 
            /// </summary>
            /// <param name="t">The text frame to fill with bytes.</param>
            /// <returns>A text frame filled with bytes read from file</returns>
            public Text InText(Text t)
            {
                t.SetPos(1);
                while (t.More() && !ENDFILE) t.PutChar(_outer.Char(InByte()));
                if (ENDFILE) t.SetPos(t.Pos() - 1);
                return t.Sub(1, t.Pos() - 1);
            }
            /// <summary>
            /// The procedure "outtext" outputs all characters in the parameter "t" as bytes. 
            /// </summary>
            /// <param name="t"></param>
            public void OutText(Text t)
            {
                t.SetPos(1);
                while (t.More()) OutByte((short)_outer.Rank(t.GetChar()));
            }
        }


        int INPUT_LINELENGTH;
        int OUTPUT_LINELENGTH;

        InFile SYSIN;
        PrintFile SYSOUT;

        public BasicIO() : this(80, 80) { }

        public BasicIO(int inputLineLength, int outputLineLength)
            : base('E', ',')
        {
            _outer = this;
            this.INPUT_LINELENGTH = inputLineLength;
            this.OUTPUT_LINELENGTH = outputLineLength;

            Prolog();
        }

        public override void Prolog()
        {
            SYSIN = new InFile("stdin");
            SYSOUT = new PrintFile("stdout");
            SYSIN.Open(Blanks(INPUT_LINELENGTH));
            SYSOUT.Open(Blanks(OUTPUT_LINELENGTH));
        }

        public override void Epilog()
        {
            SYSIN.Close();
            SYSOUT.Close();

            _openFiles.ForEach(delegate(File f) { f.Close(); });
        }

        public InFile SysIn()
        {
            return this.SYSIN;
        }

        public PrintFile SysOut()
        {
            return this.SYSOUT;
        }

        public void Terminate_Program()
        {
            Epilog();
            System.Environment.Exit(1);
        }
    }
}
